﻿using System;
using System.IO;
using System.Text;

namespace Fadd.JSON
{
	/// <summary>
	/// Used to write to a stream with tabs intact
	/// </summary>
	public class TabbedStreamWriter
	{
		private bool _firstOnLine;
		private int _intendSize;
		private readonly TextWriter _writer;
		private string _intendChars;

		/// <summary>
		/// Initializes a new instance of the <see cref="TabbedStreamWriter"/> class.
		/// </summary>
		/// <param name="stream">The stream.</param>
		/// <exception cref="ArgumentNullException"><c>stream</c> is null.</exception>
		public TabbedStreamWriter(Stream stream)
		{
			if (stream == null)
				throw new ArgumentNullException("stream");
			_writer = new StreamWriter(stream);
		}

		public TabbedStreamWriter(TextWriter writer)
		{
			_writer = writer;
		}
		/// <summary>
		/// Increase tab intend
		/// </summary>
		public void Increase()
		{
			++_intendSize;
			_intendChars = string.Empty.PadLeft(_intendSize*2);
		}

		/// <summary>
		/// Decrease tab intend.
		/// </summary>
		public void Decrease()
		{
			--_intendSize;
			_intendChars = string.Empty.PadLeft(_intendSize * 2);
		}

		/// <summary>
		/// Write a string to the stream
		/// </summary>
		/// <param name="value">value to write</param>
		/// <exception cref="System.ArgumentException">The sum of offset and count is greater than the buffer length.</exception>
		/// <exception cref="System.ArgumentNullException">buffer is null.</exception>
		/// <exception cref="System.ArgumentOutOfRangeException">offset or count is negative.</exception>
		/// <exception cref="System.IO.IOException">An I/O error occurs.</exception>
		/// <exception cref="System.NotSupportedException">The stream does not support writing.</exception>
		/// <exception cref="System.ObjectDisposedException">Methods were called after the stream was closed.</exception>
		public void Write(string value)
		{
			if (_firstOnLine)
			{
				_writer.Write(_intendChars);
				_firstOnLine = false;
			}

			_writer.Write(value);
		}

		/// <summary>
		/// Write an object to the stream
		/// </summary>
		/// <param name="value">Object to write.</param>
		/// <exception cref="System.ArgumentException">The sum of offset and count is greater than the buffer length.</exception>
		/// <exception cref="System.ArgumentNullException">buffer is null.</exception>
		/// <exception cref="System.ArgumentOutOfRangeException">offset or count is negative.</exception>
		/// <exception cref="System.IO.IOException">An I/O error occurs.</exception>
		/// <exception cref="System.NotSupportedException">The stream does not support writing.</exception>
		/// <exception cref="System.ObjectDisposedException">Methods were called after the stream was closed.</exception>
		public void Write(object value)
		{
			if (_firstOnLine)
			{
				_writer.Write(_intendChars);
				_firstOnLine = false;
			}

			_writer.Write(value);
		}

		/// <summary>
		/// Get bytes from a string.
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		protected virtual byte[] GetBytes(string value)
		{
			return Encoding.UTF8.GetBytes(value);
		}

		/// <summary>
		/// Writes a line feed to the stream.
		/// </summary>
		/// <exception cref="System.ArgumentException">The sum of offset and count is greater than the buffer length.</exception>
		/// <exception cref="System.ArgumentNullException">buffer is null.</exception>
		/// <exception cref="System.ArgumentOutOfRangeException">offset or count is negative.</exception>
		/// <exception cref="System.IO.IOException">An I/O error occurs.</exception>
		/// <exception cref="System.NotSupportedException">The stream does not support writing.</exception>
		/// <exception cref="System.ObjectDisposedException">Methods were called after the stream was closed.</exception>
		public void WriteLine()
		{
			_writer.WriteLine();
			_firstOnLine = true;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="value">Value to write.</param>
		/// <exception cref="System.ArgumentException">The sum of offset and count is greater than the buffer length.</exception>
		/// <exception cref="System.ArgumentNullException">buffer is null.</exception>
		/// <exception cref="System.ArgumentOutOfRangeException">offset or count is negative.</exception>
		/// <exception cref="System.IO.IOException">An I/O error occurs.</exception>
		/// <exception cref="System.NotSupportedException">The stream does not support writing.</exception>
		/// <exception cref="System.ObjectDisposedException">Methods were called after the stream was closed.</exception>
		public void WriteLine(string value)
		{
			Write(value);
			WriteLine();
		}

		public void Flush()
		{
			_writer.Flush();			
		}
	}
}